﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using ImapX;
using System.Xml;

namespace Eugenhome.Atrium.Mail
{
    /// <summary></summary>
    public enum ResetActions { CacheFile, Flags }

    /// <summary>
    /// 
    /// </summary>
    [XmlInclude(typeof(GadagetMessage))]
    public class GadagetMessageCollection
    {
        /// <summary></summary>
        private DAO _dao = new DAO();

        /// <summary></summary>
        private string _server;

        /// <summary></summary>
        private int _port;

        /// <summary></summary>
        private bool _ssl;

        /// <summary></summary>
        private string _user;

        /// <summary></summary>
        private string _pass;

        /// <summary></summary>
        private string _proxy;

        /// <summary></summary>
        [XmlIgnore]
        public string Method = "";

        /// <summary></summary>
        private MessageCollection _messagesCollection;

        /// <summary></summary>
        private string _cacheFullFileName = "mail.xml";// Path.GetFullPath("mail.xml");

        /// <summary></summary>
        [XmlIgnore]
        public string CacheFullFileName { get { return _cacheFullFileName; } set { _cacheFullFileName = value; } }

        /// <summary></summary>
        private bool _isFirstUpdate = true;

        /// <summary></summary>
        public List<GadagetMessage> GadagetMessageList = new List<GadagetMessage>();

        /// <summary></summary>
        [XmlIgnore]
        public List<string> Errors = new List<string>();

        /// <summary></summary>
        [XmlIgnore]
        public string PrivateKey = "";

        /// <summary></summary>
        [XmlIgnore]
        public bool Connected = false;

        /// <summary></summary>
        [XmlIgnore]
        public bool OnlineOn = true;

        /// <summary></summary>
        private GmailFeed _gmailFeed;

        /// <summary>
        /// Für die Serialisierung
        /// </summary>
        public GadagetMessageCollection() { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="server"></param>
        /// <param name="port"></param>
        /// <param name="ssl"></param>
        /// <param name="user"></param>
        /// <param name="pass"></param>
        public void SetImapMode(string server, int port, bool ssl, string user, string pass)
        {
            Method = DAO.WEBCONFIG_MAILMETHOD_VALUE_IMAP;

            _server = server;
            _port = port;
            _ssl = ssl;
            _user = user;
            _pass = pass;

            LoadCache(CacheFullFileName);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="user"></param>
        /// <param name="pass"></param>
        /// <param name="proxy"></param>
        public void SetAtomMode(string user, string pass, string proxy)
        {
            Method = DAO.WEBCONFIG_MAILMETHOD_VALUE_ATOM;

            _user = user;
            _pass = pass;
            _proxy = proxy;

            _gmailFeed = new GmailFeed(_user, _pass, _proxy);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="foldername"></param>
        /// <returns></returns>
        public List<GadagetMessage> Update(string foldername = "Inbox")
        {
            List<GadagetMessage> result = new List<GadagetMessage>();

            if (Method.Equals(DAO.WEBCONFIG_MAILMETHOD_VALUE_ATOM))
            {
                result = UpdateAtom();
            }
            else if (Method.Equals(DAO.WEBCONFIG_MAILMETHOD_VALUE_IMAP))
            {
                result = UpdateImap(foldername);
            }
            else
            {
                Errors.Add("Update-Method ist nicht gesetzt!");
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private List<GadagetMessage> UpdateAtom()
        {
            GadagetMessageList.Clear();

            _gmailFeed.DataBind();

            Errors.AddRange(_gmailFeed.Errors);

            Connected = _gmailFeed.Document != null && _gmailFeed.Errors.Count.Equals(0);

            if (Connected)
            {
                int index = 0;
                foreach (XmlNode entryNode in _gmailFeed.Document.GetElementsByTagName("entry"))
                {
                    GadagetMessage gmsg = new GadagetMessage(this);
                    gmsg.ID = index++;
                    gmsg.IsNew = true;
                    gmsg.Childs = new List<GadagetMessage>();

                    foreach (XmlNode propNode in entryNode.ChildNodes)
                    {
                        if (propNode.Name.Equals("link"))
                        {
                            gmsg.OpenLink = propNode.GetTryValue("href");
                            gmsg.RefID = propNode.GetTryValue("href");
                            int i = gmsg.RefID.IndexOf("message_id=") + 11;
                            gmsg.RefID = gmsg.RefID.Substring(i, gmsg.RefID.IndexOf("&", i) - i);
                        }
                        else if (propNode.Name.Equals("id"))
                        {
                            string id = propNode.Value;
                        }
                        else if (propNode.Name.Equals("title"))
                        {
                            gmsg.Subj = propNode.InnerText;
                        }
                        else if (propNode.Name.Equals("author"))
                        {
                            gmsg.FromName = propNode.ChildNodes[0].InnerText;
                            gmsg.From = propNode.ChildNodes[1].InnerText;
                        }
                    }

                    GadagetMessageList.Add(gmsg);
                }
            }
            return GadagetMessageList;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="foldername"></param>
        /// <returns></returns>
        private List<GadagetMessage> UpdateImap(string foldername)
        {
            List<GadagetMessage> tempGadagetMessageList = new List<GadagetMessage>();

            if (OnlineOn)
            {
                ImapClient imapClient = new ImapClient(_server, _port, _ssl);

                try
                {
                    Connected = imapClient.Connection();
                }
                catch (Exception ex) { Errors.Add("Connection: " + ex.Message); }

                if (Connected)
                {
                    try
                    {
                        Connected = imapClient.LogIn(_user, _pass);
                    }
                    catch (Exception ex) { Errors.Add("Login: " + ex.Message); }
                }

                if (Connected)
                {
                    foldername = _server.ToLower().Contains("gmail") ? "INBOX" : foldername;

                    _messagesCollection = imapClient.Folders[foldername].Messages;


                    foreach (Message msg in _messagesCollection.OrderByDescending(item => item.MessageUid))
                    {
                        GadagetMessage gmsg = GadagetMessageList.Where(item => item.ID.Equals(msg.MessageUid)).FirstOrDefault();

                        try
                        {
                            if (gmsg == null)
                            {
                                msg.ProcessFlags();
                                List<string> flags = msg.Flags;

                                msg.ProcessHeader();

                                if (flags.Count.Equals(0))
                                {
                                    msg.ProcessFlags();
                                    msg.Flags.ToList().ForEach(item => msg.RemoveFlag(item));
                                }

                                gmsg = new GadagetMessage(this, msg.MessageUid, msg.MessageId, msg.Subject, msg.From.Address, msg.From.DisplayName, msg.Flags.Count.Equals(0), msg.References);

                                tempGadagetMessageList.Add(gmsg);
                            }
                            else
                            {
                                tempGadagetMessageList.Add(gmsg);

                                if (gmsg.IsNew || _isFirstUpdate)
                                {
                                    msg.ProcessFlags();

                                    gmsg.IsNew = msg.Flags.Count.Equals(0);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Errors.Add("Update: " + ex.Message);
                        }
                    }

                    GadagetMessageList = tempGadagetMessageList;

                    Save(CacheFullFileName);

                    _isFirstUpdate = false;

                    imapClient.LogOut();
                }
            }

            //Konversationen zusammenführen

            tempGadagetMessageList = GadagetMessageList.Where(item => item.RefsString.Equals(string.Empty)).ToList();

            tempGadagetMessageList.ForEach(item => item.Childs = GadagetMessageList.Where(gmItem => gmItem.RefsString.Contains(item.RefID)).ToList());

            tempGadagetMessageList.ForEach(item => item.IsNew = (item.IsNew || item.Childs.Any(gmItem => gmItem.IsNew.Equals(true))));


            //GadagetMessageList = tempGadagetMessageList;
            return tempGadagetMessageList;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filename"></param>
        private void LoadCache(string filename)
        {
            GadagetMessageCollection loadedobj = (GadagetMessageCollection)_dao.Load(filename, this.GetType(), PrivateKey);
            Errors.AddRange(_dao.Errors);

            if (loadedobj != null)
            {
                GadagetMessageList = loadedobj.GadagetMessageList;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="resetAction"></param>
        public void Reset(params ResetActions[] resetAction)
        {
            if (resetAction.Contains(ResetActions.CacheFile))
            {
                if (File.Exists(CacheFullFileName))
                {
                    File.Delete(CacheFullFileName);
                    GadagetMessageList = new List<GadagetMessage>();
                }

                _isFirstUpdate = true;
            }

            if (resetAction.Contains(ResetActions.Flags))
            {
                _isFirstUpdate = true;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="filename"></param>
        private void Save(string filename)
        {
            _dao.Save(filename, this, PrivateKey);
            Errors.AddRange(_dao.Errors);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        public void DeleteFromServer(string id)
        {
            if (OnlineOn)
            {
                Message message = _messagesCollection.Where(item => item.MessageUid.ToString().Equals(id)).FirstOrDefault();
                if (message != null)
                {
                    ImapClient imapClient = new ImapClient(_server, _port, _ssl);

                    try
                    {
                        Connected = imapClient.Connection();
                        Connected = imapClient.LogIn(_user, _pass);
                    }
                    catch { }


                    bool result = imapClient.Folders["INBOX"].DeleteMessage(message);
                }
            }
        }

    }
}
